/* 
*
*
* This Header File Contains Huffman Compression Code
*
*
*
*  Author : Vishwajeet C. Dusane(dusanevishwajeet@yahoo.co.in)
*/

#include"Declare.h"
#include"File.h"
#include"Tree.h"

class HuffCompress
{
  //variables
   private:

 //methods
   private:
         unsigned long excedify(unsigned long );

 //variables
   public:


 //methods
   public:

  int compress(char [15],char [15]);




};




//This function is Used for converting the Exceding Number
//i.e. Number which is greater then 127
unsigned long excedify(no)
unsigned long no;
{
	int rem;
	if(no>ENO)
	{
		rem=no-ENO;
		no=128+rem;
	}
	if(no==ENO)
		no=128;
  return(no);
}
//=============================================================================




//=============================================================================
//This Function is for compression of Input file
int compress(fnmR,fnmW)
char fnmR[15];
char fnmW[15];
{
  //Variable Block : Variables used in programes
 //============================================================================
  int fpR,fpW,code,len,bit,rembit,i,size_cnt,cnt;
  unsigned int temp_code,temp_node,tempcodespace;
  unsigned long file_size=0,temp_file_size=0,codespace,mask=0,tempmask;
  char *ch,*char_write,*t,ext[3],ch_wrt[2],uch,lch;
   struct list *head_list=NULL,*min1,*min2,*temp;
 struct header *temph;
 FileReaderWriter fin;

  //End of Variable Block
 //============================================================================
	 //File Class
	 fin.readFileChar(FnmR,&head_list);

   //End of Read File and Create List
  //===========================================================================
  //Find Min Two Node from list and Create Tree For Huffman & Create Codes
   temp=head_list;
   while(temp!=NULL)
   {
	min1=head_list;
	min2=head_list->next;
	if(find_min(&head_list,&min1,&min2)==1)
	{
	 //Create Codes Here
	 code_tree(min1,0,0);
	 break;
	}
	//Creat Tree For Huffman Here
	create_tree(&head_list,&min1,&min2);
	temp=temp->next;
   }
  //End of Find Min Two Node from list and Create & Code Huffman Tree
  //============================================================================
 }
 //End of Reading Input File
//==============================================================================
 fcloseall();
 //end of creation of header
//=============================================================================
//Again Open Input File to Read
 if(fin.openFileForRead(fnmR))
 {
	printf("\n %s File not found",fnmR);
	exit(0);
 }
 else
 {
//=============================================================================
//Fetch Input File Extension
   t=strstr(fnmR,".");
   if(t==NULL)
   {
	  strcpy(ext,"svv");
		  ext[3]='\0';
   }
   else
   {
	i=0;
	t++;
	while(i<3)
	{
	  ext[i++]=*t;
	  t++;
	}
   ext[i]='\0';
   }
//End of Create New File Name And Fetch Input File Extension
//============================================================================
//Create New File
   if(fin.openForWrite(fnmW))
   {
	printf("\n %s File Already Exist OR Enable to create new file",fnmW);

	exit(0);
   }
   else
   {
	 //Code to Write Header TotalNode To New File as 1 & 2 byte
	 char_write=(char *)malloc(1);
	 temp_node=head_header->tot_node;
	 temp_node=temp_node>>8;
	 *char_write=(char)temp_node;
	 if(fin.writeIntoOutFile(char_write,1)!=1)
	 {
	   printf("\nFile writing error");
	   exit(0);
	 }
	 temp_node=head_header->tot_node;
	 temp_node=temp_node<<8;
	 temp_node=temp_node>>8;
	 *char_write=(char)temp_node;
	 if(fin.writeIntoOutFile(char_write,1)!=1)
	 {
	   printf("\nFile writing error");
	   exit(0);
	 }
  //End of Write Header TotalNode To New File
//==============================================================================//Code To Write InputFile Extension as 3 & 4 & 5 byte To New File
  free(char_write);
  char_write=(char *)malloc(3);
  char_write=ext;
  strcpy(char_write,ext);
  if(fin.writeIntoOutFile(char_write,3)!=3)
	  {
	   printf("\nFile writing error");
	   exit(0);
	  }
 //End of Write InputFile Extension To New File
//=============================================================================
//Code To Write InputFile size to New File as 6-10 bytes
  char_write=(char *)malloc(1);
  temp_file_size=file_size>>24;
  temp_file_size=temp_file_size<<8;
  temp_file_size=temp_file_size>>8;
  *char_write=(char)temp_file_size;
  if(fin.writeIntoOutFile(char_write,1)!=1)
  {
	printf("\nFile writing error");
	exit(0);
  }
  char_write=(char *)malloc(1);
  temp_file_size=file_size>>16;
  temp_file_size=temp_file_size<<8;
  temp_file_size=temp_file_size>>8;
  *char_write=(char)temp_file_size;
  if(fin.writeIntoOutFile(char_write,1)!=1)
  {
   printf("\nFile writing error");
   exit(0);
  }
  char_write=(char *)malloc(1);
  temp_file_size=file_size>>8;
  temp_file_size=temp_file_size<<8;
  temp_file_size=temp_file_size>>8;
  *char_write=(char)temp_file_size;
  if(fin.writeIntoOutFile(char_write,1)!=1)
  {
	printf("\nFile writing error");
	exit(0);
  }
  char_write=(char *)malloc(1);
  temp_file_size=file_size;
  temp_file_size=temp_file_size<<8;
  temp_file_size=temp_file_size>>8;
  *char_write=(char)temp_file_size;
  if(fin.writeIntoOutFile(char_write,1)!=1)
  {
   printf("\nFile writing error");
   exit(0);
  }
  //End of Write InputFile size to New File
 //=======================================================================
 //Code To Calculate Header Size and Write To New File
  temph=head_header;
  codespace=0;
  tempcodespace=0;
  while (temph!=NULL)
  {
	if((temph->depth%8)>0)
	  tempcodespace=(temph->depth/8)+2+1;
	else
	  tempcodespace=(temph->depth/8)+2;
	codespace=codespace+tempcodespace;
	temph=temph->next;
   }
   tempcodespace=0;
   char_write=(char *)malloc(1);
   tempcodespace=codespace>>24;
   tempcodespace=tempcodespace<<8;
   tempcodespace=tempcodespace>>8;
   *char_write=(char)tempcodespace;
   if(fin.writeIntoOutFile(char_write,1)!=1)
   {
	 printf("\nFile writing error");
	 fcloseall();
	 exit(0);
   }
   tempcodespace=0;
   char_write=(char *)malloc(1);
   tempcodespace=codespace>>16;
   tempcodespace=tempcodespace<<8;
   tempcodespace=tempcodespace>>8;
   *char_write=(char)tempcodespace;
   if(fin.writeIntoOutFile(char_write,1)!=1)
   {
	 printf("\nFile writing error");
	 fcloseall();
	 exit(0);
   }
   tempcodespace=0;
   char_write=(char *)malloc(1);
   tempcodespace=codespace>>8;
   tempcodespace=tempcodespace<<8;
   tempcodespace=tempcodespace>>8;
   *char_write=(char)tempcodespace;
   if(fin.writeIntoOutFile(char_write,1)!=1)
   {
	 printf("\nFile writing error");
	 fcloseall();
	 exit(0);
	}
	tempcodespace=0;
	char_write=(char *)malloc(1);
	tempcodespace=codespace;
	tempcodespace=tempcodespace<<8;
	tempcodespace=tempcodespace>>8;
	*char_write=(char)tempcodespace;
	if(fin.writeIntoOutFile(char_write,1)!=1)
	{
	  printf("\nFile writing error");
	  fcloseall();
	  exit(0);
	 }
  //End of Write Header Size to New File
//=============================================================================
  //Code to Write Header To New File as Char Depth Code
	 temph=head_header;
	 while(temph!=NULL)
	 {
	free(char_write);
	char_write=(char *)malloc(1);
	//char_write=NULL;
	*char_write=(char)temph->ch;
	if(fin.writeIntoOutFile(char_write,1)!=1)
	{
	  printf("\nFile writing error");
	  fcloseall();
	  exit(0);
	}
	free(char_write);
	char_write=(char *)malloc(1);
	//char_write=NULL;
	*char_write=(char)temph->depth;
	if(fin.writeIntoOutFile(char_write,1)!=1)
	{
	  printf("\nFile writing error");
	  fcloseall();
	  exit(0);
	}
  //Break up Code into Parts if Depth > 8 and Write Each Part as a character
	temp_code=0;
	cnt=0;
	if(temph->depth>8)
	{
	cnt=temph->depth/8;
		if((temph->depth%8)>0)
	  cnt=cnt+1;
   //Here cnt is Number of Bytes needed for Code
  //Writting For right side bytes First
	for(cnt=cnt-1;cnt>=0;cnt--)
	{
	 free(char_write);
	 char_write=(char *)malloc(1);
	 if(cnt>0)
	  temp_code=temph->code>>(8*cnt);
	 else
	  temp_code=temph->code;
	 temp_code=temp_code<<8;
	 temp_code=temp_code>>8;
	 *char_write=(char)temp_code;
	 if(fin.writeIntoOutFile(char_write,1)!=1)
	 {
	  printf("\nFile writing error");
	  fcloseall();
	  exit(0);
	 }
	}
	//end of For Loop
	  }
	  //End of if depth>8
	  else
	  {
	temp_code=temph->code;
	temp_code=temp_code<<8;
	temp_code=temp_code>>8;
	*char_write=(char)temp_code;
	if(fin.writeIntoOutFile(char_write,1)!=1)
	{
	  printf("\nFile writing error");
	  fcloseall();
	  exit(0);
	}
	  }
	  //end of else of if depth > 8
	  temph=temph->next;
	 }
  //End of Write Header to New File
//============================================================================
 //Here We Read Each Character From Input File and Writes it's code to new File
	 /* replace andmask by var which will be written to file as char replace
	 andmask=7<<3;replace 7 by andmask & 3 by current char depth
	 andmask=andmask|3;replace 3 by current char code
	 if andmask exited 256 then take rem=andmask-256
	 write 256 as file char and assign andmask to rem and continue loop
	if andmask is 8 bits write to file
	*/

   bit=0;
   mask=0;
   free(char_write);
   char_write=(char *)malloc(1);
   file_size=0;
   while(fin.readInFile()!=EOF)
   {
	 file_size=file_size+1;
	 temph=head_header;
	 //Code to search for Input file character in header
	 while(temph!=NULL)
	 {
	   if(temph->ch==(*ch))
	   {
	 //Here If Character from input file matches with header
	 //Then fetch it's code and depth and corresponding code to New File
	 code=temph->code;
	 len=temph->depth;
	 break;
	   }
	   temph=temph->next;
	  }
	 //end of search for Input file character in header
   mask=mask<<len;
   mask=excedify(mask);
   mask=mask|code;
   mask=excedify(mask);
  bit=bit+len;
  //If Constructed code is of 8 bit long then write it to New File
  if(bit==8)
  {
	*char_write=(char)mask;
	if(fin.writeIntoOutFile(char_write,1)!=1)
	{
	  printf("\nFile writing error");
	  fcloseall();
	  exit(0);
	}
	mask=0;
	bit=0;
   }
  //End of bit==8
  //If Constructed code is > 8 bit long then write first 8 bits form left           as chacter to it to New File until less than 8 bits
   if(bit>8)
   {
	 while(bit>8)
	 {
	   rembit=32-bit;
	   mask=mask<<rembit;
	   mask=excedify(mask);
	  tempmask=mask;
	  tempmask=excedify(tempmask);
//Take Left most 8 bits and write to New File First
	  tempmask=tempmask>>24;
	  tempmask=excedify(tempmask);
	  *char_write=(char)tempmask;
	  if(fin.writeIntoOutFile(char_write,1)!=1)
	  {
		printf("\nFile writing error");

	exit(0);
	  }
	  mask=mask<<8;
	  mask=excedify(mask);
	  mask=mask>>8;
	  mask=mask>>rembit;
	  mask=excedify(mask);
	 bit=bit-8;
	}
	//end of while code length > 8 bits
   }
   //end of if code length > 8 bits
  }
  //End of Read Input File
 //==========================================================================
  //If some bits are remaining in code then write those to New File
   bit=8-bit;
   mask=mask<<bit;
   mask=excedify(mask);
   *char_write=(char)mask;
	if(fin.writeIntoOutFile(char_write,1)!=1)
	{
	  printf("\nFile writing error");
	  fcloseall();
	  exit(0);
	 }
   }
   //End of Writing New File
//============================================================================
 }
 //End of Reading Input file
//============================================================================
fcloseall();
system("clear");
printf("\nGiven File is successfully Compressed with ''%s'' name \n",fnmW);
//make compressed file read only by system call chmod
/*if (chmod(fnmW, S_IREAD) != 0)
  {
	printf("\nFile Created But Unable to change file mode");
	getch();
	exit(0);
  } */
  //end of make compressed file read only by system call chmod
  return 0;
//End Of Compression Of Input File As New File
}
//End of Compress Function
//============================================================================